﻿/*
 * @author: wizardc
 */

using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace Dou.UI
{
    /// <summary>
    /// 单选按钮
    /// 1. 未设置 group 时，为复选框状态，可以任意选择或取消；
    /// 2. 设置 group 时，为单选组下的一个单选框状态，其自身状态受到组中其它单选框影响；
    /// </summary>
    public class DToggle : Selectable, IPointerClickHandler, ISubmitHandler
    {
        [Serializable]
        public class ToggleEvent : UnityEvent<bool> {}
        
        [SerializeField]
        private bool _isOn;
        [SerializeField]
        private bool _useGray = false;
        [SerializeField]
        private ToggleEvent _onValueChanged = new ToggleEvent();
        
        private DToggleGroup _group;
        
        /// <summary>
        /// 所属单选组
        /// </summary>
        public DToggleGroup group => _group;

        /// <summary>
        /// 是否选中
        /// </summary>
        public bool isOn
        {
            set => SetIsOn(value);
            get => _isOn;
        }
        
        /// <summary>
        /// 是否置灰
        /// </summary>
        public bool useGray
        {
            set
            {
                if (_useGray != value)
                {
                    _useGray = value;
                    UIUtil.SetGray(transform, _useGray);
                }
            }
            get => _useGray;
        }
        
        /// <summary>
        /// 当前组件选中状态改变时
        /// </summary>
        public ToggleEvent onValueChanged
        {
            set => _onValueChanged = value;
            get => _onValueChanged;
        }
        
        protected override void OnEnable()
        {
            base.OnEnable();
            onValueChanged?.Invoke(_isOn);
        }
        
        /// <summary>
        /// 设置是否选中
        /// </summary>
        private void SetIsOn(bool value)
        {
            if (_isOn == value)
            {
                return;
            }
            
            // 有单选组的情况
            if (_group != null && _group.isActiveAndEnabled && IsActive())
            {
                // 允许全部都是未选中的情况
                if (_group.allowSwitchOff)
                {
                    if (value)
                    {
                        _group.SetToggleOn(this);
                    }
                    else
                    {
                        _isOn = false;
                        onValueChanged?.Invoke(_isOn);
                        // 通知没有任何选项被选中
                        _group.onChanged?.Invoke(-1);
                    }
                }
                // 至少会有一个必然被选中的情况
                else
                {
                    // 没有任何被选中，就强制选中当前当前按钮
                    if (!_group.AnyTogglesOn())
                    {
                        if (!_isOn)
                        {
                            _isOn = true;
                            onValueChanged?.Invoke(_isOn);
                        }
                        _group.SetToggleOn(this, false);
                    }
                    // 该情况下不允许直接设置自己的 isOn 为 false 的，必须是组内其它按钮设置为 true 后顶替掉自己的状态
                    else if (value)
                    {
                        _group.SetToggleOn(this);
                    }
                }
            }
            // 没有单选组的情况
            else
            {
                _isOn = value;
                onValueChanged?.Invoke(_isOn);
            }
        }
        
        internal void SetIsOn()
        {
            if (!_isOn)
            {
                _isOn = true;
                onValueChanged?.Invoke(_isOn);
            }
        }

        internal void SetIsOff()
        {
            if (_isOn)
            {
                _isOn = false;
                onValueChanged?.Invoke(_isOn);
            }
        }
        
        internal void SetToggleGroup(DToggleGroup group)
        {
            _group = group;
        }
        
        public void OnPointerClick(PointerEventData eventData)
        {
            if (eventData.button != PointerEventData.InputButton.Left)
            {
                return;
            }
            InternalToggle();
        }
        
        private void InternalToggle()
        {
            if (!IsActive() || !IsInteractable())
            {
                return;
            }
            isOn = !isOn;
        }
        
        public void OnSubmit(BaseEventData eventData)
        {
            InternalToggle();
        }
        
        protected override void OnDestroy()
        {
            if (_group != null)
            {
                _group.UnregisterToggle(this);
            }
            base.OnDestroy();
        }
    }
}
